package cheme.ProcessModel.ModelActions;

import org.eclipse.gef.commands.CompoundCommand;

import cheme.ProcessModel.IModelElement;
import cheme.ProcessModel.ModelEnv;
import cheme.ProcessModel.ProcessModelConstants;
import cheme.ProcessModel.Cmds.AddCmd;
import cheme.ProcessModel.Cmds.ChemeActionCommand;
import cheme.ProcessModel.Cmds.DeleteCmd;
import cheme.ProcessModel.Cmds.IChemeCommand;
import cheme.ProcessModel.Cmds.ReplaceCmd;
import cheme.ProcessModel.Cmds.SetModelSelectionCmd;
import cheme.ProcessModel.Cmds.SetModelTextCmd;
import cheme.ProcessModel.Equations.Equation;
import cheme.ProcessModel.Equations.EquationField;
import cheme.ProcessModel.Equations.EquationList;
import cheme.ProcessModel.Equations.IEquationField;
import cheme.ProcessModel.Interpreter.Interpreter;
import cheme.ProcessModel.Interpreter.ModelElementData;
import cheme.ProcessModel.ProcessUnits.Streams.Tags.ITagComponentField;
import cheme.ProcessModel.ProcessUnits.Streams.Tags.TagComponent;
import cheme.ProcessModel.ProcessUnits.Streams.Tags.TagComponentList;
import cheme.ProcessModel.Table.Field;

public class PostupdateModelActionFactory extends AbstractModelActionFactory
{
	
	public PostupdateModelActionFactory()
	{
//		CommandActionMap baseMap = new CommandActionMap()
//		{
//			public Boolean test(Object target)
//			{
//				return (target instanceof SetModelTextCmd);
//			}
//		};
//		
//		CommandActionMap nestedMap = new CommandActionMap()
//		{
//			public Boolean test(Object target)
//			{
//				
//				return (null != target &&
//						target instanceof IChemeCommand && 
//						((IChemeCommand)target).getSource() instanceof ITagComponentField);
//			}
//		};
//		
//		baseMap.add(nestedMap);
//		baseMap = nestedMap;
//		
//		nestedMap = new CommandActionMap()
//		{
//			public Boolean test(Object target)
//			{
//				
//				return (null != target &&
//						target instanceof IChemeCommand && 
//						((IChemeCommand)target).getSource() instanceof ITagComponentField);
//			}
//		};
//		
//		baseMap.add(nestedMap);
//		
//		nestedMap = new CommandActionMap()
//		{
//			public Boolean test(Object target)
//			{
//				
//				return (null != target &&
//						target instanceof IChemeCommand && 
//						((IChemeCommand)target).getSource() instanceof ITagComponentField);
//			}
//		};
//		
//		baseMap.add(nestedMap);
		
//		xif(originalCmd instanceof SetModelTextCmd)
//		{
//			if(source instanceof ITagComponentField)
//			{
//				if(((Field)source).getParent() instanceof TagComponent)
//				{
//					cmd.add(new EnsureDefaultComponentCmd(((Field)source).getParent().getParent()));
//				}
//			}
//			else if(source instanceof IEquationField)
//			{
//				cmd.add(new EnsureDefaultEquationCmd((Field)source.getParent().getParent()));
//			}
//		}
	}
	
	public CompoundCommand getActions(IChemeCommand originalCmd)
	{
		IModelElement source = (IModelElement)originalCmd.getSource();
		CompoundCommand cmd = new CompoundCommand(); 
		
		if(originalCmd instanceof SetModelTextCmd)
		{
			if(source instanceof ITagComponentField)
			{
				if(((Field)source).getParent() instanceof TagComponent)
				{
					cmd.add(new EnsureDefaultComponentCmd(((Field)source).getParent().getParent()));
				}
			}
			else if(source instanceof IEquationField)
			{
				cmd.add(new EnsureDefaultEquationCmd((Field)source.getParent().getParent()));
			}
		}
		if(originalCmd instanceof SetModelSelectionCmd)
		{
			if(source instanceof ITagComponentField)
			{
				if(((Field)source).getParent() instanceof TagComponent)
				{
					cmd.add(new EnsureDefaultComponentCmd(((Field)source).getParent().getParent()));
				}
			}
		}
		else if(originalCmd instanceof ReplaceCmd)
		{
			if(source instanceof IEquationField)
			{
//				cmd.add(new HookEquationTokenCmd(((Field)source).getParent()));
				
				/*
				 * Since by the time this is executed the field will not have a parent, this command wants the parent now
				 * and will consider that the source rather than the actual field. 
				 */
				cmd.add(new EnsureDefaultEquationCmd(((Field)source).getParent().getParent()));
				cmd.add(new EnsureDefaultEquationTokenCmd(((Field)source).getParent()));
			}
		}
		else if(originalCmd instanceof AddCmd)
		{
			if(source instanceof IEquationField)
			{
//				cmd.add(new HookEquationTokenCmd(source));
			}
			else if(source instanceof Equation)
			{
				cmd.add(new EnsureDefaultEquationCmd(((Equation)source).getParent()));
				cmd.add(new EnsureDefaultEquationTokenCmd((Equation)source));
			}
		}
		else if(originalCmd instanceof DeleteCmd)
		{
			if(source instanceof TagComponent)
			{
				cmd.add(new EnsureDefaultComponentCmd(((TagComponent)source).getParent()));
			}
			else if(source instanceof Equation)
			{
				cmd.add(new EnsureDefaultEquationCmd(((Equation)source).getParent()));
				cmd.add(new EnsureDefaultEquationTokenCmd((Equation)source));
			}
		}
		
		return cmd;
	}

	class HookEquationTokenCmd extends ChemeActionCommand
	{
		public HookEquationTokenCmd(Object source)
		{
			super(source);
		}
		
		@Override
		public Equation getSource()
		{
			return (Equation)super.getSource();
		}

		@Override
		public void execute()
		{
			Interpreter interpreter = ModelEnv.getInstanceFor(getSource()).getInterpreter();
			ModelElementData data = null;
			
			for(Field field : getSource().getChildren())
			{
				/*
				 * Note that this code never is concerned with removal of listeners 
				 * as that is handled pre-command in an unhook action
				 */
				
				/*
				 * Add the new...
				 */
				if(interpreter.modelExists(field.getText()))
				{
					data = interpreter.getModelData(field.getText());
					data.getModel().addPropertyChangeListener(field);
				}
			}
		}

		@Override
		public void undo()
		{
		}
	}
	
	class EnsureDefaultEquationTokenCmd extends ChemeActionCommand
	{
		boolean add = false;
		EquationField addElement = null;
		
		public EnsureDefaultEquationTokenCmd(Object source)
		{
			super(source);
		}
		
		@Override
		public Equation getSource()
		{
			return (Equation)super.getSource();
		}

		@Override
		public void execute()
		{
			if(!getSource().getChildren().isEmpty())
			{
				EquationField lastToken = (EquationField)getSource().getChildren().get(getSource().getChildren().size() - 1);
				
				if(!lastToken.getText().isEmpty())
				{
					add = true;
				}
			}
			else
			{
				add = true;
				
			}
					
			if(true == add)
			{
				addElement = (EquationField)ModelEnv.getInstanceFor(getSource()).createModelElement(ProcessModelConstants.EQUATION_FIELD, getSource());
				getSource().add(addElement);
			}
		}

		@Override
		public void redo()
		{
			if(true == add)
			{
				getSource().add(addElement);
			}
		}
		
		@Override
		public void undo()
		{
			if(true == add)
			{
				getSource().remove(addElement);
			}
		}
	}

	class EnsureDefaultEquationCmd extends ChemeActionCommand
	{
		boolean add = false;
		Equation addElement = null;
		
		public EnsureDefaultEquationCmd(Object source)
		{
			super(source);
		}
		
		@Override
		public EquationList getSource()
		{
			return (EquationList)super.getSource();
		}

		@Override
		public void execute()
		{
			if(!getSource().getChildren().isEmpty())
			{
				Equation lastComponent = (Equation)getSource().getChildren().get(getSource().getChildren().size() - 1);
						
				if(!lastComponent.isInitial())
				{
					add = true;
				}
			}
			else
			{
				add = true;
				
			}
					
			if(true == add)
			{
				addElement = (Equation)ModelEnv.getInstanceFor(getSource()).createModelElement(ProcessModelConstants.EQUATION, getSource());
				getSource().add(addElement);
			}
		}

		@Override
		public void redo()
		{
			if(true == add)
			{
				getSource().add(addElement);
			}
		}
		
		@Override
		public void undo()
		{
			if(true == add)
			{
				getSource().remove(addElement);
			}
		}
	}
	
	class EnsureDefaultComponentCmd extends ChemeActionCommand
	{
		boolean add = false;
		TagComponent addElement = null;
		
		public EnsureDefaultComponentCmd(Object source)
		{
			super(source);
		}
		
		@Override
		public TagComponentList getSource()
		{
			return (TagComponentList)super.getSource();
		}

		@Override
		public void execute()
		{
			if(!getSource().getChildren().isEmpty())
			{
				TagComponent lastComponent = (TagComponent)getSource().getChildren().get(getSource().getChildren().size() - 1);
						
				if(!lastComponent.isInitial())
				{
					add = true;
				}
			}
			else
			{	
				add = true;
			}
					
			if(true == add)
			{
				addElement = (TagComponent)ModelEnv.getInstanceFor(getSource()).createModelElement(ProcessModelConstants.TAG_COMPONENT, getSource());
				getSource().add(addElement);
			}
		}

		@Override
		public void redo()
		{
			if(true == add)
			{
				getSource().add(addElement);
			}
		}
		
		@Override
		public void undo()
		{
			if(true == add)
			{
				getSource().remove(addElement);
			}
		}
	}
}
	